package cn.biplam.back.bean.tool.flat;

import java.util.ArrayList;
import java.util.List;

import cn.biplam.common.client.DbResource;
import cn.biplam.common.paramters.MdParam;
import cn.biplam.common.paramters.ModelType.Model_Type;
import cn.biplam.common.struc.BaseStruc.IndexTableStruc;
import cn.biplam.common.wrapper.ErrorMessage;
import cn.biplam.common.wrapper.treeFlat.PcNode;
import cn.biplam.common.wrapper.treeFlat.flat.callback.CompareCallback;
import cn.biplam.common.wrapper.treeFlat.flat.callback.OperatorTypeFilterCallback;
import cn.biplam.common.wrapper.treeFlat.flat.callback.ParentFieldNameCallback;
import cn.biplam.common.wrapper.treeFlat.flat.callback.CompareCallback.Compare_Type;
import cn.biplam.common.wrapper.treeFlat.pcTree.TablePcTree;
import cn.biplam.common.wrapper.treeFlat.pcTree.callback.OperatorTypeCallback;
import cn.biplam.common.wrapper.treeFlat.pcTree.callback.OperatorTypeCallbackImp;

/**
 *  父子关系表到平面关系表转换器<BR>
 *  <P>用法:<BR>
 *    1 创建转换器(父子表表名称,父子表数据源)<BR>
 *    2 设置父子表对应父子关系的字段名 setPcFieldMap(ID字段名,父亲ID字段名,名称字段,级别字段)<BR>
 *    3 (可选)设置父子关系表附加字段名称 putAddFields(List)<BR>
 *    4 (可选)设置被过滤的节点     setDataFilter(List)<BR>
 *    
 *   5 (可选)设置平面表表名   setTargetTableName()<B>如果未设置平面表表名为：父子表表名+"_Flat"</B><BR>
 *   6 (可选)设置平面表数据源 setTargetDbResource()<B>如果未设置平面表数据源为父子表数据源</B><BR>
 *   7 (可选)设置平面化后数据过滤条件 setOperatorTypeFilterCallback,setOperatorTypeFieldName,根据节点类型过滤<BR>
 *  </P>
 * @author XiaoRuxing Nov 28, 20093:22:48 PM
 * @version 1.0
 */
public class PcTableToFlatTableImp {

	private TablePcTree pcTree;
	private FlatToDb flatToDb;

	/** 记录ID字段名 */
	private String nodeIdField;
	/** 父亲ID字段名 */
	private String nodeParentField;
	/** 节点名称字段名 */
	private String nodeNameField;
	/** 业务级别字段名 */
	private String nodeLevelField;

	private DbResource pcTableDbResource;
	/** 父子关系表表名称 */
	private String pcTabName;
	/** 目标表表名称 */
	private String trgTabName;
	/** 目标数据源 */
	private DbResource trgDbResource;
	/** 操作类型字段名 */
	protected String operatorTypeFieldName;
	/** 获取父亲们字段名称的回调器 */
	private ParentFieldNameCallback parentFieldNameCallback;
	/** 平面化数据过滤器 */
	private OperatorTypeFilterCallback filterCallback;

	private final static String Extent_Table_Name = "_Flat";

	/**
	 * @param tableName 表名称
	 * @param dbReource 表数据源(可以为空)
	 * @throws ErrorMessage
	 */
	public PcTableToFlatTableImp(String tableName,
			DbResource dbReource) throws ErrorMessage{
		this.pcTree = new TablePcTree(tableName, dbReource);
		this.pcTabName = tableName;
		this.pcTableDbResource = dbReource;
	}

	/**
	 *  设置父子表字段名称映射<BR>
	 *  记录ID,父亲ID,节点名称和业务级别对应的字段名称
	 * @param nodeIdField     记录ID字段名
	 * @param nodeParentIdField 父亲ID字段名
	 * @param nodeNameField   节点名称字段名
	 * @param nodeLevelField  业务级别字段名(可以为空)
	 */
	public void setPcFieldMap(String nodeIdField,
			String nodeParentIdField,
			String nodeNameField, 
			String nodeLevelField){
		this.nodeIdField = nodeIdField;
		this.nodeParentField = nodeParentIdField;
		this.nodeNameField = nodeNameField;
		this.nodeLevelField = nodeLevelField;
		this.pcTree.setFieldMap(nodeIdField, nodeParentIdField, nodeNameField, nodeLevelField);
	}

	/**
	 *  放入附加数据字段
	 * @param field 附加数据字段(一个附加字段的情况下使用)
	 */
	public void putAddFields(
			String field){
		this.pcTree.setOperatorCallback(new OperatorTypeCallbackImp(field));
		this.pcTree.putAddFields(field);
	}
	
	/**
	 *  放入附加数据字段
	 * @param fields 附加数据字段(可以是一个或者多个字段,此方法可以多次调用)
	 */
	public void putAddFields(OperatorTypeCallback operatorFields,
			String... fields){
		this.pcTree.setOperatorCallback(operatorFields);
		this.pcTree.putAddFields(fields);
	}

	/**
	 * 设置过滤数据列表 
	 * @param filterList 被过滤的节点列表(存储的内容为节点ID)
	 */
	public void setDataFilter(List<String> filterList){
		this.pcTree.setDataFilter(filterList);
	}

	/**
	 *  设置根节点条件回调器
	 * @param parentCallback 根节点条件回调器
	 */
	public void setRootNodeCallBack(CompareCallback parentCallback){
		this.pcTree.setRootNodeCallBack(parentCallback);
	}
	
	/**
	 *  设置目标表表名称
	 * @param tableName 表名称
	 */
	public void setTargetTableName(String tableName){
		this.trgTabName = tableName;
	}

	/**
	 *  设置目标数据源
	 * @param trgDb 目标数据源
	 */
	public void setTargetDbResource(DbResource trgDb){
		this.trgDbResource = trgDb;
	}

	/**
	 *  设置父亲们字段名称回调器<BR>
	 *  生成每个父亲的ID和名称字段名
	 * @param parentFieldNameCallback 父亲们字段名称回调器
	 */
	public void setParentFieldNameCallback(
			ParentFieldNameCallback parentFieldNameCallback){
		this.parentFieldNameCallback = parentFieldNameCallback;
	}

	/**
	 *  设置节点操作类型字段名称
	 * @param operatorTypeFieldName 节点操作类型字段
	 */
	public void setOperatorTypeFieldName(String operatorTypeFieldName){
		this.operatorTypeFieldName = operatorTypeFieldName;
	}

	/**
	 *  设置节点操作类型过滤回调器
	 */
	public void setOperatorTypeFilterCallback(OperatorTypeFilterCallback callback){
		this.filterCallback = callback;
	}
	
	/**
	 *  
	 * @return 平面表名称
	 */
	public String getFlatTableName(){
		return this.trgTabName;
	}

	/**
	 *  
	 * @return 获取平面表字段列表
	 */
	public ArrayList<String> getFieldList(){
		return this.flatToDb.fieldNameList();
	}

	/**
	 *  
	 * @return 执行数据转换
	 * @throws ErrorMessage 
	 */
	public boolean execute() throws ErrorMessage{
		//获取树形数据
		PcNode pcNode = this.pcTree.get();
		//创建平面化数据
		this.flatToDb = new FlatToDb(pcNode);
		//设置目标表名称,如果未设置目标表则目标表为原始表名+_Flat
		if(this.trgTabName == null){
			this.trgTabName = this.pcTabName+Extent_Table_Name;
		}
		this.flatToDb.setTargetTableName(this.trgTabName);
		//目标数据源
		if(this.trgDbResource == null){
			this.trgDbResource = pcTableDbResource;
		}
		this.flatToDb.setTargetDbResource(this.trgDbResource);
		//设置字段
		this.flatToDb.setNodeIdField(nodeIdField);
		this.flatToDb.setNodeLevelField(nodeLevelField);
		this.flatToDb.setNodeNameField(nodeNameField);
		this.flatToDb.setParentFieldName(nodeParentField);
		this.flatToDb.setParentFieldNameCallback(parentFieldNameCallback);
		this.flatToDb.setOperatorTypeFieldName(operatorTypeFieldName);
		this.flatToDb.setOperatorTypeFilterCallback(filterCallback);
		return this.flatToDb.toDb(true);
	}

	public static void main(String[] args) throws ErrorMessage {
		PcTableToFlatTableImp table = new PcTableToFlatTableImp(MdParam.Table_Name,
				new DbResource());
		table.setPcFieldMap(IndexTableStruc.NODE_ID, 
				IndexTableStruc.NODE_PARENT, IndexTableStruc.NODE_NAME, null);
		table.setRootNodeCallBack(new CompareCallback("-1",IndexTableStruc.NODE_PARENT,Compare_Type.Equal));
		table.putAddFields(IndexTableStruc.NODE_TYPE);
		table.setOperatorTypeFilterCallback(new IndexTableOperatorFilter());
		table.execute();
	}
}
/**
 * 索引表节点类型过滤器
 */
class IndexTableOperatorFilter implements OperatorTypeFilterCallback{

	public boolean isFilter(String operatorType) {
		if(operatorType.equals(Model_Type.Src.toString())){
			return false;//未被过滤
		}else{
			return true;//被过滤
		}
	}

}
